/* -*- C++ -*- */
/*\*\*
 
 .---=||||[ B L O O D Y ]|||||\*\*----------....
 |                                                              |
 |    THE  M O S T   B L O O D Y  GAME EVER!                    |
 |                                                              |
 |    bloody harvest is coming... soon,                         |
 |                                              heil Satan!     |
 !                                                              !
 .                                                              ,
  ~~~~-------------\*\*-~




 Name-Space: core
 Module: exceptions
 Purpose: Provide basic exception system
 Last modification:  barzto, 07/05/2006

 TODO:

 FIX:

 
 
 \*\**/


#ifndef __core_exceptions_header_file__
#define __core_exceptions_header_file__
#include "common.h"
#include <exception>
#include "types.h"
namespace core
{
	/**
	 * Base class for all exception classes.
	 */
	class BaseException : public std::exception
	{
	public:

		/**
		 * Constructor for generating error message. Creates message based
		 * on fmt and possible addition arguments.
		 * 
		 * @param fmt Formating string, same as for printf
		 */
		BaseException(const char* fmt, ...) throw();

		/**
		 * Copy constructor. Creates new BaseException object using data from
		 * src object.
		 * 
		 * @param src Source object
		 */
		BaseException(const BaseException& src);

		/**
		 * Copy operator. Copies new date from rhs object and frees the olde one.
		 * 
		 * @param rhs Right hand side operand of assign operator.
		 * @return Reference to self
		 */
		BaseException& operator=(const BaseException& rhs);

		/**
		 * Exception destructor. Frees message memory.
		 */
		virtual ~BaseException() throw();

		/** 
		 * Returns a C-style character string describing the general cause
		 * of the current error.  
		 * 
		 * @return Exception message
		 */
		virtual const char * what() const throw()
		{
			return const_cast<const char*>(message);
		}
	protected:

		/**
		 * Message describing raised exception.
		 */
		char* message;
	};

	/**
	 * Class containing information about out-of-range exception.
	 */
	class OutOfRangeException : public BaseException
	{
	public:
		/**
		 * Basic constructor of OutOfRangeException object.
		 * 
		 * @param rgMin minimal value of range.
		 * @param rgMax maximal value of range.
		 * @param curVal value, that gets out of defined range.
		 */
		OutOfRangeException(u32 rgMin, u32 rgMax, u32 curVal);

		/**
		 * Copy constructor. Creates new OutOfRangeException object using data from
		 * src object.
		 * 
		 * @param src Source object
		 */
		OutOfRangeException(const OutOfRangeException& src);

		/**
		 * Copy operator. Copies new date from rhs object and frees the olde one.
		 * 
		 * @param rhs Right hand side operand of assign operator.
		 * @return Reference to self
		 */
		OutOfRangeException& operator= (const OutOfRangeException& rhs);

		/**
		 * Gets value of minimal range.
		 * @return value of minimal range.
		 */
		u32 getRangeMin() const 
		{
			return rangeMin;
		}

		/**
		 * Gets value of minimal range.
		 * @return value of minimal range.
		 */
		u32 getRangeMax() const 
		{
			return rangeMax;
		}

		/**
		 * Gets value, that gets out of range and causes this exception.
		 * @return value that gets out of defined range.
		 */
		u32 getCurrentVal() const 
		{
			return currentVal;
		}

	protected:

		/**
		 * Minimal value of range
		 */
		u32 rangeMin;

		/**
		 * Maximal value of range
		 */
		u32 rangeMax;

		/**
		 * Value that gets out of definied range.
		 */
		u32 currentVal;
	};

	class FileNotFoundException : public BaseException
	{
	public:
		FileNotFoundException(const char* file);

		/**
		 * Copy constructor. Creates new FileNotFoundException object using data from
		 * src object.
		 * 
		 * @param src Source object
		 */
		FileNotFoundException(const FileNotFoundException& src);

		/**
		 * Copy operator. Copies new date from rhs object and frees the olde one.
		 * 
		 * @param rhs Right hand side operand of assign operator.
		 * @return Reference to self
		 */
		FileNotFoundException& operator= (const FileNotFoundException& rhs);

		const char* getFileName() const
		{
			return fileName;
		}
	private:
		const char* fileName;
	};

	/**
	 * Exception representing generic invalid operation case.
	 */
	class InvalidOperationException : public BaseException
	{
	public:
		/**
		 * Creates new Exception about Invalid Operations.
		 * 
		 * @param desc Message describing invalid operations,
		 * that currently happens.
		 */
		InvalidOperationException(const char* desc) : BaseException("Invalid Operation: %s", desc)
		{}
	};
	

	/**
	 * Exception araised within OpenGL operations.
	 */
	struct GLException : public BaseException
	{
			/**
			 * Creates new exception, based on OpenGL exception.
			 *
			 * @param err Error code (from glGetError())
			 */
			GLException(GLenum err)
				:BaseException("GLException: %s", errStr(err)),glError(err)
			{}

			/**
			 * Checks if there is no OpenGL error. If such error is
			 * detected, araise GLException reflecting this error.
			 */
			static void check()
			{ 
				GLenum err = glGetError();
				if (GL_NO_ERROR != err)
				{
					throw GLException(err);
				}
			}

		private:
			/**
			 * Gets error message from OpenGL error enumeration.
			 */
			static const char* errStr(GLenum err)
			{
				const char* ret = "No error";
				switch (err)
				{

					case GL_NO_ERROR:
						ret = "No error";
						break;

					case GL_INVALID_ENUM:
						ret = "Invalid enumeration";
						break;

					case GL_INVALID_VALUE:
						ret = "Invalid value";
						break;

					case GL_INVALID_OPERATION:
						ret = "Invalid operation";
						break;

					case GL_STACK_OVERFLOW:
						ret = "Stack overflow";
						break;

					case GL_STACK_UNDERFLOW:
						ret = "Stack underflow";
						break;

					case GL_OUT_OF_MEMORY:
						ret = "Out of memory";
						break;

					case GL_TABLE_TOO_LARGE:
						ret = "Table too large";
						break;

					default:
						ret = "Unknown error";
				}

				return ret;
						
			}

			GLenum glError;
	};

	class ILException : public BaseException  {
	public:
	  
	  ILException(ILenum errorCode, const char* nfo = 0)
	    : BaseException("IL error: %s, %s", errStr(errorCode), (nfo) ? nfo: "" ) {}
	  
	private:
	  const char* errStr(ILenum errCode){
	    const char* ret;
	    switch (errCode) {
	    case IL_NO_ERROR:
	      ret = "No Error ;)";
	      break;

	    case IL_INVALID_ENUM:
	      ret = "Invalid enumeration";
	      break;

	    case IL_OUT_OF_MEMORY:
	      ret = "Out of Memory";
	      break;

	    case IL_FORMAT_NOT_SUPPORTED:
	      ret = "Format not supported";
	      break;

	    case IL_INTERNAL_ERROR:
	      ret = "IL internal error";
	      break;

	    case IL_INVALID_VALUE:
	      ret = "Invalid value";
	      break;

	    case IL_ILLEGAL_OPERATION:
	      ret = "Illegal operation";
	      break;

	    case IL_ILLEGAL_FILE_VALUE:
	      ret = "Illegal file value";
	      break;

	    case IL_INVALID_FILE_HEADER:
	      ret = "Invalid file header";
	      break;

	    case IL_INVALID_PARAM:
	      ret = "Invalid parameter";
	      break;

	    case IL_COULD_NOT_OPEN_FILE:
	      ret = "Could not open file";
	      break;

	    case IL_INVALID_EXTENSION:
	      ret = "Invalid extension";
	      break;

	    case IL_FILE_ALREADY_EXISTS:
	      ret = "File already exists";
	      break;

	    case IL_OUT_FORMAT_SAME:
	      ret = "Out Format Same";
	      break;

	    case IL_STACK_OVERFLOW:
	      ret = "Stack overflow";
	      break;

	    case IL_STACK_UNDERFLOW:
	      ret = "Stack underflow";
	      break;

	    case IL_INVALID_CONVERSION:
	      ret = "Invalid conversion";
	      break;

	    case IL_BAD_DIMENSIONS:
	      ret = "Bad dimensions";
	      break;

	    case IL_FILE_READ_ERROR:
	      ret = "File I/O error";
	      break;

	    case IL_LIB_GIF_ERROR:
	      ret = "LibGif error";
	      break;

	    case IL_LIB_JPEG_ERROR:
	      ret = "LibJpeg error";
	      break;

	    case IL_LIB_PNG_ERROR:
	      ret = "LibPng error";
	      break;

	    case IL_LIB_TIFF_ERROR:
	      ret = "LibTiff error";
	      break;

	    case IL_LIB_MNG_ERROR:
	      ret = "LibMng error";
	      break;
	    
	    case IL_UNKNOWN_ERROR:
	    default:
	      ret = "Unknown error";
	    }

	    return ret;
	  }
	};
}

#endif //__core_exceptions_header_file__

